﻿
using java.util;
using java.util.zip;
using java.io;
using System;
namespace WB.Library
{
    public class Compress
    {

        #region Main Method

        #region Zip
        /// <summary>
        /// Zip file or folder
        /// </summary>
        /// <param name="srcPath">Source to compress(File/Folder)</param>
        /// <param name="desPath">Destination file</param>
        /// <param name="isContainFolder">
        /// True: Zip file contains Folder structure
        /// False: Zip file only contains all file in all sub folder
        /// </param>
        /// <param name="isDeleteSrcFile">Delete after compress</param>
        public static void ZipFile(String srcPath, String desPath, bool isContainFolder, bool isDeleteSrcFile)
        {
            File f = new File(srcPath);

            System.IO.FileInfo fInfo = new System.IO.FileInfo(desPath);
            if (!System.IO.Directory.Exists(fInfo.DirectoryName))
                System.IO.Directory.CreateDirectory(fInfo.DirectoryName);


            if (f.isFile())
            {
                zipFile(srcPath, desPath, isDeleteSrcFile);
            }
            else
            {
                if (isContainFolder)
                    zipDirectory(srcPath, desPath, isDeleteSrcFile);
                else
                    zipFileWithoutDirectory(srcPath, desPath, isDeleteSrcFile);
            }


        }
        #endregion


        #region Unzip
        /**
* Extract a zip file in to dirTo
* @param from : file.zip
* @param dirTo : Directory to extract
* @see: unzipFile("D:/test.zip","D:/unzip");
*/
        public static void UnzipFile(String from, String dirTo, bool isDeleteSrcFile)
        {
            System.IO.FileInfo fInfo = new System.IO.FileInfo(dirTo);
            if (!System.IO.Directory.Exists(fInfo.DirectoryName))
                System.IO.Directory.CreateDirectory(fInfo.DirectoryName);


            BufferedOutputStream outStream = null;
            ZipInputStream inStream = new ZipInputStream
            (new BufferedInputStream(new FileInputStream(from)));
            ZipEntry entry;
            while ((entry = inStream.getNextEntry()) != null)
            {
                String fileSrc = new File(entry.getName()).getPath();
                //vResult.add(fileSrc);
                String fileDes = dirTo + "/" + fileSrc;

                File fTemp = new File(fileDes);

                if (entry.isDirectory())
                {
                    System.IO.Directory.CreateDirectory(fTemp.getPath());
                }
                else
                {
                    int count;
                    sbyte[] data = new sbyte[4096];
                    outStream = new BufferedOutputStream(new
                    FileOutputStream(fileDes), 4096);
                    while ((count = inStream.read(data, 0, 4096)) != -1)
                    {
                        outStream.write(data, 0, count);
                    }
                    outStream.flush();
                    outStream.close();
                }
            }
            inStream.close();
            //if chose delete file after unzip, delete the zip file
            if (isDeleteSrcFile)
                (new File(from)).delete();
        }
        #endregion

        #endregion


        #region ZipFile
        /**
* Compress file to *.zip file
* @param from : File to compress
* @param to : Destination file after compress
* @see: zipFile("D:/test.txt","D:/test.rar");
* @throws IOException
*/
        protected static void zipFile(String from, String to, bool isDeleteSrcFile)
        {
            //create input stream
            FileInputStream inStream = new FileInputStream(from);
            //create output stream to compress file

            ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(to));
            File f = new File(from);
            //create an entry of zip file
            ZipEntry entry = new ZipEntry(f.getName()); // Make a ZipEntry
            outStream.putNextEntry(entry); // Store entry
            sbyte[] buffer = new sbyte[4096];
            int bytesRead;
            //read bytes to compress
            while ((bytesRead = inStream.read(buffer)) != -1)
                outStream.write(buffer, 0, bytesRead);
            inStream.close();
            outStream.close();
            if (isDeleteSrcFile)
                f.delete();
        }


        /**
        * Compress files in fromDir into a zipFile
        * @param fromDir
        * @param zipfile
        * @throws IOException
        * @throws IllegalArgumentException
        */
        protected static void zipFileWithoutDirectory(String fromDir, String zipfile, bool isDeleteSrcFile)
        {
            // Check that the directory is a directory, and get its contents
            File d = new File(fromDir);
            String[] entries = d.list();
            sbyte[] buffer = new sbyte[4096]; // Create a buffer for copying
            int bytesRead;

            ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(zipfile));

            for (int i = 0; i < entries.GetLength(0); i++)
            {
                File f = new File(d, entries[i]);
                if (f.isDirectory())
                {
                    zipSubFile(f.getPath(), outStream, isDeleteSrcFile);
                }
                else
                {
                    FileInputStream inStream = new FileInputStream(f); // Stream to read file
                    ZipEntry entry = new ZipEntry(f.getName()); // Make a ZipEntry
                    outStream.putNextEntry(entry); // Store entry
                    while ((bytesRead = inStream.read(buffer)) != -1)
                        outStream.write(buffer, 0, bytesRead);
                    inStream.close();
                    if (isDeleteSrcFile)
                        f.delete();
                }
            }
            outStream.close();
        }

        /*
        * Zip sub file/and folder
        * EX: D:
        * |_ Parent
        * |_SubFolder1 _ text1.tzt
        * |_ text2.txt
        * |_ SubFolder2
        * Call zipDirectory("D:\Parent","D:\test.zip",false)
        * When compress at SubFolder1, we have to call zipSubDirectory("D:\Parent","D:\Parent\SubFolder1",outStream,isDeleteSrcFile)
        * --> this method compress file and directory with root path is "D:\Parent"
        * test.zip
        * |_SubFolder1 _ text1.tzt
        * |_ text2.txt
        * |_ SubFolder2
        *
        */
        protected static void zipSubFile(String fromDir, ZipOutputStream outStream, bool isDeleteSrcFile)
        {
            // Check that the directory is a directory, and get its contents
            File d = new File(fromDir);
            String[] entries = d.list();
            sbyte[] buffer = new sbyte[4096]; // Create a buffer for copying
            int bytesRead;

            for (int i = 0; i < entries.GetLength(0); i++)
            {
                File f = new File(d, entries[i]);
                if (f.isDirectory())
                {
                    zipSubFile(f.getPath(), outStream, isDeleteSrcFile);
                }
                else
                {
                    FileInputStream inStream = new FileInputStream(f); // Stream to read file
                    ZipEntry entry = new ZipEntry(f.getName()); // Make a ZipEntry
                    outStream.putNextEntry(entry); // Store entry
                    while ((bytesRead = inStream.read(buffer)) != -1)
                        outStream.write(buffer, 0, bytesRead);
                    inStream.close();
                    if (isDeleteSrcFile)
                        f.delete();
                }
            }
        }
        #endregion ZipFile

        #region ZipFolder
        /**
* Compress files in fromDir into a zipFile
* @param fromDir
* @param zipfile
* @throws IOException
* @throws IllegalArgumentException
*/
        public static void zipDirectory(String fromDir, String zipfile, bool isDeleteSrcFile)
        {
            // Check that the directory is a directory, and get its contents
            File d = new File(fromDir);
            String[] entries = d.list();
            sbyte[] buffer = new sbyte[4096]; // Create a buffer for copying
            int bytesRead;

            ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(zipfile));

            for (int i = 0; i < entries.GetLength(0); i++)
            {
                File f = new File(d, entries[i]);

                /*if exist subfolder, zip subfolder with the path after cut parentpath
                EX: D:
                |_ Parent
                |_SubFolder1 _ text1.tzt
                |_ text2.txt
                |_ SubFolder2
                Call zipDirectory("D:\Parent","D:\test.zip",false)
                When compress at SubFolder1, we have to call zipSubDirectory("D:\Parent","D:\Parent\SubFolder1",outStream,isDeleteSrcFile)
                --> this method compress file and directory with root path is "D:\Parent"
                test.zip
                |_SubFolder1 _ text1.tzt
                |_ text2.txt
                |_ SubFolder2

                */
                if (f.isDirectory())
                {
                    zipSubDirectory(fromDir, f.getPath(), outStream, isDeleteSrcFile);
                }
                else
                {
                    FileInputStream inStream = new FileInputStream(f); // Stream to read file
                    ZipEntry entry = new ZipEntry(f.getName()); // Make a ZipEntry
                    outStream.putNextEntry(entry); // Store entry
                    while ((bytesRead = inStream.read(buffer)) != -1)
                        outStream.write(buffer, 0, bytesRead);
                    inStream.close();
                    if (isDeleteSrcFile)
                        f.delete();
                }
            }
            outStream.close();
        }
        /*
        * Zip sub file/and folder
        * EX: D:
        * |_ Parent
        * |_SubFolder1 _ text1.tzt
        * |_ text2.txt
        * |_ SubFolder2
        * Call zipDirectory("D:\Parent","D:\test.zip",false)
        * When compress at SubFolder1, we have to call zipSubDirectory("D:\Parent","D:\Parent\SubFolder1",outStream,isDeleteSrcFile)
        * --> this method compress file and directory with root path is "D:\Parent"
        * test.zip
        * |_SubFolder1 _ text1.tzt
        * |_ text2.txt
        * |_ SubFolder2
        *
        */
        protected static void zipSubDirectory(String rootDir, String fromDir, ZipOutputStream outStream, bool isDeleteSrcFile)
        {
            // Check that the directory is a directory, and get its contents
            File d = new File(fromDir);
            String[] entries = d.list();
            sbyte[] buffer = new sbyte[4096]; // Create a buffer for copying
            int bytesRead;

            for (int i = 0; i < entries.GetLength(0); i++)
            {
                File f = new File(d, entries[i]);
                if (f.isDirectory())
                {
                    zipSubDirectory(rootDir, f.getPath(), outStream, isDeleteSrcFile);
                }
                else
                {
                    FileInputStream inStream = new FileInputStream(f); // Stream to read file
                    ZipEntry entry = new ZipEntry(f.getPath().Replace(rootDir + "\\", "")); // Make a ZipEntry
                    outStream.putNextEntry(entry); // Store entry
                    while ((bytesRead = inStream.read(buffer)) != -1)
                        outStream.write(buffer, 0, bytesRead);
                    inStream.close();
                    if (isDeleteSrcFile)
                        f.delete();
                }
            }
        }
        #endregion ZipFolder




        //#region Run Test
        //public static void Main(String[] args)
        //{

        //    //Zip file
        //    Compress.ZipFile("D:/ZIP_UNZIP/Source/testCompress.txt", "D:/ZIP_UNZIP/Destination/testCompress.zip", true, false);

        //    //Zip Folder
        //    Compress.ZipFile("D:/ZIP_UNZIP/Source/FolderCompress", "D:/ZIP_UNZIP/Destination//FolderCompress.zip", true, false);
        //    Compress.ZipFile("D:/ZIP_UNZIP/Source/FolderCompress", "D:/ZIP_UNZIP/Destination//FolderCompressToOnfile.zip", false, false);

        //    //Unzip file
        //    Compress.UnzipFile("D:/ZIP_UNZIP/Source/folderUnzip.zip", "D:/ZIP_UNZIP/Destination/folderUnzip", false);


        //}

        //#endregion

    }
}
